package com.itheima.p2_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * demo01代理
 *
 * @author 86183
 * @date 2022/11/05
 */
public class Demo01Proxy {
    /**
     * 主要
     *
     * @param args arg游戏
     * @throws Exception 异常
     */
    public static void main(String[] args) throws Exception {
        //多态的方式创建Human接口实现类对象
        Human human = new SpringBrother();
        //调用方法
        human.dance(50000);
        human.sing(30000);
        human.eat();
        System.out.println("=================");
         /*
            java.lang.reflect.Proxy类:
                作用: jdk提供的用来创建代理对象
                静态方法:
                    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h):
                    方法作用:创建代理对象的
                    方法参数:
                        1.ClassLoader loader: 类加载器对象
                            作用: 用来加载产生的代理类的,传递被代理对象的类加载对象
                        2.Class<?>[] interfaces: 被代理对象实现的接口的Class对象数组
                            因为被代理对象可能会实现多个接口
                            java.lang.Class类内部定义方法:
                            public Class<?>[] getInterfaces(): 获取当前类实现的所有的接口的Class对象数组
                        3.InvocationHandler h: 接口,用来指定产生的代理类对被代理类如何进行代理的
                            传递实现类/匿名内部类的对象
         */
        //获取被代理对象的Class对象
        Class<? extends Human> clazz = human.getClass();
        //1.获取被代理对象的类加载器对象
        ClassLoader classLoader = clazz.getClassLoader();
        //2.获取被代理对象所属类实现的所有的接口的Class对象数组
        Class<?>[] interfaces = clazz.getInterfaces();
        //3.多态的方式创建InvocationHandler接口的匿名内部类对象,指定对被代理类如何代理
        InvocationHandler invocationHandler = new InvocationHandler() {
            /*
                invoke方法:
                    1.作用: 用来指定对被代理类如何代理
                    2.参数:
                        (1)Object proxy: 产生的代理对象,目前对我们来说没有用
                        (2)Method method: 代理对象调用的方法的Method对象,本质是接口中对应的方法的Method对象
                        (3)Object[] args: 代理对象调用方法时传递的参数,被封装为了Object数组
                    3.注意:
                        (1)invoke方法: 就相当于门卫,只要进入这个房间,门卫就得拦着你
                        (2)使用代理对象调用方法,都必须经过invoke方法
                    4.返回值:
                        java.lang.Object类: 执行被代理对象方法后返回的结果
                        返回到哪里去呢? 在哪里使用代理对象调用方法,返回到哪里
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                //定义一个Object对象,保存方法执行后的结果
                Object obj = null;
                if ("dance".equals(methodName)) {
                    System.out.println("我的人跳舞开始...");
                    //执行被代理对象的方法
                    method.invoke(human,args);
                    System.out.println("我的人跳舞结束...");
                } else if ("sing".equals(methodName)) {
                    System.out.println("我的人唱歌开始...");
                    //执行被代理对象的方法
                     method.invoke(human,args);
                    System.out.println("我的人唱歌结束...");
                } else if ("eat".equals(methodName)) {
                    System.out.println("我的人吃饭开始...");
                    //执行被代理对象的方法
                    method.invoke(human,args);
                    System.out.println("我的人吃饭结束...");
                }
                return null;
            }
        };
        //4.使用Proxy类调用静态方法newProxyInstance获取代理对象
        Human humanProxy = (Human) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        //5.使用产生的代理对象调用方法
        humanProxy.dance(50000f);
        humanProxy.sing(30000f);
        humanProxy.eat();

    }
}
